#include"Event.h"
#include <numeric>

int MaxTime(const int m, vector<vector <int> >& map_graph, vector<int>& weight_value)
{
	const int n = m;//node number
	int des = 0, num = 0, ff = 0;
	int max_value = Min;//des check whether it is a destination node;min_value use to compute the maxmine value
	vector <int> comp, inde;//dist are distance from 0 node to other nodes; inde, comp, num, ff use to find the minimun distance
	vector <int> dist;
	dist.resize(m);
	inde.resize(m);
	comp.resize(m);
	for (int i = 0; i<n; i++)//add weight of the map_graph
		for (int j = 0; j<n; j++)
		{
			if (map_graph[i][j] != Min)
				map_graph[i][j] += weight_value[j];
		}
	for (int i = 0; i<n; i++)//initialize the dist and inde
	{
		dist[i] = map_graph[0][i];
		inde[i] = false;
	}
	inde[0] = true;
	while (des != (n - 1))
	{
		num = 0;
		max_value = Min;
		for (int i = 1; i<n; i++)//record the nodes which is not labeled and we will find the minimum node from these nodes 
		{
			if (inde[i] == false)
				comp[num++] = i;
		}
		for (int i = 0; i<num; i++)//find the minimum node's value
		{
			ff = comp[i];
			max_value = max(dist[ff], max_value);
		}
		for (int i = 0; i<num; i++)//find the minimum node's number by minimum value
		{
			ff = comp[i];
			if (dist[ff] == max_value)
				des = ff;
		}
		inde[des] = true;//we find the minimum value and mark this node true
		for (int i = 0; i<n; i++)//change the dist to this minimum node and add the minimum value
		{
			if (inde[i] == false)
				dist[i] = map_graph[des][i] + max_value;
		}
	}
	for (int i = 1; i<n; i++)//add the first node's weight value
	{
		dist[i] += weight_value[0];
	}

	//cout << endl;
	return dist[n - 1];
}
int calculateTimeFromMap(vector<vector <int> > edges,vector<int> nodes) {
	int executionTime = *(max_element(nodes.begin(),nodes.end()));
	int communicationTime = *(max_element(edges[0].begin(), edges[0].end()));
	return executionTime + communicationTime;
}
int variance(vector<int> a) {
	return *max_element(a.begin(), a.end()) - (*min_element(a.begin(), a.end()));
}
bool distanceComp(vector<int>a, vector<int>b) {

	bool small = true;

	if (a.size() == 0 && b.size() == 0) {
		return false;
	}
	if (a.size() == 0) {
		return true;
	}
	if (b.size() == 0) {
		return false;
	}

	int sumA = std::accumulate(a.begin(), a.end(), 0);
	int sumB = std::accumulate(b.begin(), b.end(), 0);
	if (sumA > sumB) {
		return !small;
	}
	else {
		if (sumA < sumB) {
			return small;
		}
		else {

			int varianceA = variance(a);
			int varianceB = variance(b);
			if (varianceA > varianceB) {
				return small;
			}
			else {
				return !small;
			}
		}
	}
}
double thermalModel(int sum2, int centerP, int sum12, int sum11) {
	//return 59.9 + 0.0097*centerP + 0.0008*sum12 + 0.0002*sum11 + 0.00015*(sum2 - sum12 - sum11);
	if (centerP >= 1) {
		switch (sum11) {
		case 4:
			return 61;
			break;
		case 3:
			if (sum12 > 1) {
				return 61;
			}
			else {
				if (sum12 == 1) {
					if (sum2 > 15) {
						return 61;
					}
					else {
						return 0;
					}
				}
				else {
					return 0;
				}
			}
			break;
		case 2:
			if (sum12 > 2) {
				return 61;
			}
			else {
				if (sum12 == 2) {
					if (sum2 > 12) {
						return 61;
					}
					else {
						return 0;
					}
				}
				else {
					return 0;
				}
			}
			break;
		case 1:
			if (sum11 >= 4) {
				return 61;
			}
			else {
				return 0;
			}
			break;
		case 0:
			return 0;
			break;
		}
	}
	else {
		return  0;
	}
}
int sum2(int x, int y, Map map) {
	int result = 0;
	for (int i = x - 2; (i >= x - 2) && (i <= x + 2); i++) {
		for (int j = y - 2; (j >= y - 2) && (j <= y + 2); j++) {
			if (i >= 0 && j >= 0 && i < map.getWidth()&&j < map.getHeight()&&map.getSpecificCore(Vertex(0,j,i))->checkState()) {
				result += 1;
			}
		}
	}
	return result;
}
int sum12(int x, int y, Map map) {
	int result = 0;
	int CoreWidth = map.getWidth();
	if (x - 1 >= 0 && y - 1 >= 0 && map.getSpecificCore(Vertex(0,y-1,x-1))->checkState()) {
		result++;
	}
	if (x + 1 <= CoreWidth - 1 && y + 1 <= CoreWidth - 1 && map.getSpecificCore(Vertex(0, y + 1, x + 1))->checkState()) {
		result++;
	}
	if (x + 1 <= CoreWidth - 1 && y - 1 >= 0 && map.getSpecificCore(Vertex(0, y - 1, x + 1))->checkState()) {
		result++;
	}
	if (y + 1 <= CoreWidth - 1 && x - 1 >= 0 && map.getSpecificCore(Vertex(0, y + 1, x - 1))->checkState()) {
		result++;
	}
	return result;
}
int sum11(int x, int y, Map map) {
	int result = 0;
	int CoreWidth = map.getWidth();
	if (x - 1 >= 0 && map.getSpecificCore(Vertex(0, y, x-1))->checkState()) {
		result++;
	}
	if (x + 1 <= CoreWidth - 1 && map.getSpecificCore(Vertex(0, y, x + 1))->checkState()) {
		result++;
	}
	if (y - 1 >= 0 && map.getSpecificCore(Vertex(0, y - 1, x))->checkState()) {
		result++;
	}
	if (y + 1 <= CoreWidth - 1 && map.getSpecificCore(Vertex(0, y + 1, x))->checkState()) {
		result++;
	}
	return result;
}
int thermalThreshold = 60;
bool thermalCheckCore(Vertex v, Map map) {
	bool overHeat = false;
	double temp = thermalModel(sum2(v.w, v.h,map), 1, sum12(v.w, v.h,map), sum11(v.w, v.h, map));
	if (temp > thermalThreshold) {
		overHeat = true;
	}
	
	return false;
}
bool thermalCheckMap(Map map) {
	int width = map.getWidth();
	int height = map.getHeight();

	bool overHeat = false;
	for (int y = 0; y < height; y++) {
		for (int x = 0; x < width; x++) {
			if (map.getSpecificCore(Vertex(0, y, x))->checkState() != -1) {
				int sum2x = sum2(x, y, map);
				int sum12x = sum12(x, y, map);
				int sum11x = sum11(x, y, map);
				double temp = thermalModel(sum2x, 1, sum12x, sum11x);
				if (temp > thermalThreshold) {
					//map.showMap();
					overHeat = true;
					sum11x = sum11(x, y, map);
					return true;
					//cout << "overHeat!!" << endl;
					//map.showMap();
				}
			}
		}
	}

	return false;
}


Event::Event(Application a) {//warning: havn't initialize shape yet
	vector<Task> raw = a.getTasks();
	for (auto t : raw) {
		tasks.push_back(InvokedTask(t));
	}
	taskGraph = a.getTaskGraph();
	arrivalTime = a.getArrivalTime();
	numTasks = tasks.size();
	id = a.getId();
}

bool Event::arrive(int now) {
	if (arrivalTime == now) {
		return true;
	}
	return false;
}

void Event::updateTaskGraph()
{
	for (int i = 0; i < numTasks; i++) {
		taskGraph[i] = tasks[i].unprocessedData();
	}
}

void Event::showTaskGraph()
{
	for (auto i : taskGraph) {
		for (auto j : i) {
			cout << j << '\t';
		}
		cout << endl;
	}
}

bool Event::startRunning(Map* map,int type) {
	state = running;
	startTime = Clock::getClock()->now();
	if (settleDown(map,type)) {
		//map->showMap();
		if (thermalCheckMap(*map)) {
			unhookFromMap(map);
			return false;
		}
		else {
			return true;
		}
	}
	return false;
}

Shape Event::packing(Map map,int bubbleNum) {
	Shape shape(numTasks + bubbleNum);
	shape.rectangle();
	if (shape.height > map.getHeight() || shape.width > map.getWidth()) {
		shape.fittingMap();
		if (shape.height > map.getHeight() || shape.width > map.getWidth()) {
			shape.width = map.getWidth();
			shape.height = ceil(double(numTasks + bubbleNum) / shape.width);
		}
	}
	return shape;
}

Vertex Event::book(Map map, int bubbleNum, vector<Vertex>notwork) {
	//Shape shape = packing(map);
	int coreCNT = 0;
	if (map.getAvailableCores() > numTasks + bubbleNum) {
		Map mapMask = map;
		for (int l = 0; l < map.getLength() && coreCNT < numTasks + bubbleNum; l++) {
			for (int h = 0; h < map.getHeight() && coreCNT < numTasks + bubbleNum; h++) {
				for (int w = 0; w < map.getWidth() && coreCNT < numTasks + bubbleNum; w++) {
					Vertex temp(l, h, w);
					if (!(std::find(notwork.begin(), notwork.end(), temp) != notwork.end())) {
						if ((!map.getSpecificCore(temp)->checkState())) {
							mapMask.getSpecificCore(temp)->turnOn(id, coreCNT);
							if (!thermalCheckMap(mapMask)) {
								coreCNT++;
							}
							else {
								mapMask.getSpecificCore(temp)->turnOff();
							}
							if (coreCNT == numTasks + bubbleNum) {
								return temp;
							}
						}
					}
				}
			}
		}
	}
	return Vertex(-1, -1, -1);// mark that can't find a suitable vertex
}
	
	

bool Event::mapping(Map* map,int type) {
	//return randomMapping(map);
	//return serialMapping(pin,shape, map);
	//return CEMapping(pin, shape, map);

	//return farestMapping_pin(pin, map);
	Vertex pin = book(*map);
	if (pin == Vertex(-1, -1, -1)) {
		//map->showMap();
		return false;
	}
	switch (type) {
	case 0:
		return cloestMapping_pin(pin,map);
	case 1:
		return farestMapping_pin(map);
	case 2:
		return proposedMapping(map);
	}
	//return !thermalCheckMap(*map);
}

bool Event::settleDown(Map* map,int type) {
	/*Vertex pin = book(*map);
	if (pin == Vertex(-1, -1, -1)) {
		map->showMap();
		return false;
	}
	vector<Vertex> notwork;
	bool valid = mapping(pin, map, type);
	int count = 0;
	while (!valid) {
		notwork.push_back(pin);
		pin = book(*map,0, notwork);
		valid = mapping(pin, map, type);
		count++;
		if (count == map->getAvailableCores()) {
			break;
		}
	}*/
	
	return mapping(map, type);
	//Shape shape = packing(*map);
	//return valid;
}

double Event::communicationCost(Map map) {
	double communicationCost = 0;
	for (auto task:tasks) {
		vector<int> p = task.getParents();
		vector<double> v = task.getWithNeibors();
		if (!p.empty()) {
			for (auto pi: p) {
				communicationCost += tasks[pi].getLandlord().Manhattan(task.getLandlord()) * v[pi];
			}
		}
	}

	return communicationCost;
}

void Event::finish(Map* map) {
	state = finished;
	finishTime = Clock::getClock()->now();
	unhookFromMap(map);
}

void Event::unhookFromMap(Map* map) {
	for (int i = 0; i < numTasks;i++) {
		if (tasks[i].checkState() != unmapped) {
			map->turnOffCore(tasks[i].getLandlord());
			tasks[i].release();
		}
	}
	
}

int Event::calculateRemainingTime(Map* map) {
	vector<vector<int>> edges;
	vector<int> nodes;
	for (int i = 0; i < numTasks;i++) {
		auto task = tasks[i];
		auto c = map->getSpecificCore(task.getLandlord());
		vector<int> line;
		for (int j = 0; j < numTasks; j++) {
			if (i != j) {
				double data = taskGraph[i][j] > 0 ? taskGraph[i][j] : 0;
				int length = task.getLandlord().Manhattan(tasks[j].getLandlord());
				line.push_back((data + 0.5) / (length * c->getInputSpeed()));
			}
			else {
				line.push_back(0);
			}
		}
		edges.push_back(line);

		nodes.push_back(task.predictExecutionTime(c->getExecutionSpeed()));
	}

	int eT = 0;
	for (auto each : nodes) {
		eT += each;
	}

	int cT = 0;
	for (auto line : edges) {
		for (auto each : line) {
			cT += each;
		}
	}
	return eT + cT;
	//return 1;
}

void Event::nRound(Map* map, int n) {
	for (int i = 0; i < numTasks; i++) {
		InvokedTask* t = &tasks[i];
		Core* c = map->getSpecificCore(t->getLandlord());
		int es = c->getExecutionSpeed();
		vector<double> input;
		vector<double> output;
		vector<double> need = t->unprocessedData();
		for (int j = 0; j < numTasks;j++) {
			if (i != j && need[j] != 0) {
				int length = tasks[j].getLandlord().Manhattan(t->getLandlord());
				input.push_back(c->getInputSpeed()/(double)length);
				output.push_back(-c->getOutputSpeed()/ (double)length);
			}
			else {
				input.push_back(0);
				output.push_back(0);
			}
		}

		bool tick = true;
		vector<int> p = t->getParents();
		State s = t->checkState();
		switch (s) {
		case waiting:
			if (p.empty()) {
				t->setState(executing);
			}
			else {
				tick = false;
				for (auto pi : p) {
					if (tasks[pi].checkState() == tranfering) {
						tick = true;
					}
				}
				if (tick) {
					t->setState(receiving);
				}
			}
			break;
		case receiving:
			t->nRound(0, input);
			break;
		case executing:
			t->nRound(es, vector<double>(numTasks,0));
			break;
		case tranfering:
			t->nRound(0, output);
			break;
		case finished:
			t->nRound(0, vector<double>(numTasks, 0));
			break;
		}
	}
	
	updateTaskGraph();
	if (calculateRemainingTime(map) == 0) {
		finish(map);
	}
}

bool Event::hasFinished() {
	return state == State::finished;
}

void Event::wait() {
	state = waiting;
}

int Event::getArrivalTime() {
	return arrivalTime;
}

int Event::getStartTime() {
	return startTime;
}

int Event::getFinishTime() {
	return finishTime;
}

int Event::getNumTasks() {
	return  numTasks;
}

vector<InvokedTask> Event::getTasks() {
	return tasks;
}

int Event::getId() {
	return id;
}

bool Event::serialMapping(Vertex pin,Shape shape,Map* map) {
	bool valid = true;
	int count = 0;
	for (int k = pin.l; k < pin.l + shape.length && count < numTasks; k++) {
		for (int i = pin.h; i < pin.h + shape.height && count < numTasks; i++) {
			for (int j = pin.w; j < pin.w + shape.width && count < numTasks; j++) {
				Vertex temp(k, i, j);
				if (!map->getSpecificCore(temp)->checkState()) {
					if (valid && thermalCheckCore(temp, *map)) {
						if (temp == Vertex(pin.l + shape.length - 1, pin.h + shape.height - 1, pin.w + shape.width - 1)) {
							valid = false;
						}
						else {
							map->turnOnCore(tasks[count],temp);
							tasks.at(count).startRunning(temp);
							count++;
						}
					}
				}
			}
		}
	}

	//map->updateAvailableCores(-numTasks);
	return valid;
}

/*bool Event::farestMapping(Vertex pin, Shape shape, Map* map) {
	vector<Vertex> occupied;
	vector<vector<int>> distance;
	for (int k = pin.l; k < pin.l + shape.length; k++) {
		for (int i = pin.h; i < pin.h + shape.height; i++) {
			for (int j = pin.w; j < pin.w + shape.width; j++) {
				vector<int> plate;
				distance.push_back(plate);
				Vertex temp(k,i,j);
				if (map->getSpecificCore(temp)->checkState()) {
					occupied.push_back(temp);
				}
			}
		}
	}
	
	for (vector<Vertex>::iterator iter = occupied.begin(); iter != occupied.end(); iter++) {
		for (int k = pin.l; k < pin.l + shape.length; k++) {
			for (int i = pin.h; i < pin.h + shape.height; i++) {
				for (int j = pin.w; j < pin.w + shape.width; j++) {
					Vertex temp(k,i, j);
					Vertex diff = temp - pin;
					int diffI = diff.l*shape.height*shape.width + diff.h*shape.width + diff.w;
					if (!map->getSpecificCore(temp)->checkState()) {
						distance[diffI].push_back((*iter).Manhattan(temp));
					}
					else {
						distance[diffI].clear();
					}
				}
			}
		}
	}

	for (int count = 0; count < numTasks; count++) {
		int location = std::distance(distance.begin(), max_element(distance.begin(), distance.end(), distanceComp));
		Vertex selectedCore = Vertex(pin.l,pin.h+location/shape.width,pin.w+location%shape.width);
		map->getSpecificCore(selectedCore)->turnOn(tasks.at(count).getApplicationId(), tasks.at(count).getId());
		tasks.at(count).startRunning(selectedCore);

		occupied.push_back(selectedCore);
		for (int k = pin.l; k < pin.l + shape.length && count < numTasks; k++) {
			for (int i = pin.h; i < pin.h + shape.height && count < numTasks; i++) {
				for (int j = pin.w; j < pin.w + shape.width && count < numTasks; j++) {
					Vertex temp(k,i,j);
					Vertex diff = temp - pin;
					int diffI = diff.l*shape.height*shape.width + diff.h*shape.width + diff.w;
					if (!map->getSpecificCore(temp)->checkState()) {
						distance[diffI].push_back(selectedCore.Manhattan(temp));
					}
					else {
						distance[diffI].clear();
					}
				}
			}
		}
	}
	map->updateAvailableCores(-numTasks);
	return true;
}

bool Event::CEMapping(Vertex pin, Shape shape, Map* map) {
	bool valid = true;
	Vertex center(pin.l + shape.length / 2, pin.h + shape.height / 2, pin.w + shape.width / 2);
	map->getSpecificCore(center)->turnOn(tasks.at(0).getApplicationId(), tasks.at(0).getId());
	tasks.at(0).startRunning(center);
	
	int count = 1;
	//for (int k = center.l;)


	for (int k = pin.l; k < pin.l + shape.length && count < numTasks; k++) {
		for (int i = pin.h; i < pin.h + shape.height && count < numTasks; i++) {
			for (int j = pin.w; j < pin.w + shape.width && count < numTasks; j++) {
				Vertex temp(k, i, j);
				if (!map->getSpecificCore(temp)->checkState()) {
					if (valid && thermalCheckCore(temp, *map)) {
						if (temp == Vertex(pin.l + shape.length - 1, pin.h + shape.height - 1, pin.w + shape.width - 1)) {
							valid = false;
						}
					}
					else {
						map->getSpecificCore(temp)->turnOn(tasks.at(count).getApplicationId(), tasks.at(count).getId());
						tasks.at(count).startRunning(temp);
						map->updateAvailableCores(-1);
						count++;
					}
				}
			}
		}
	}
	if (count != numTasks) {
		valid = false;
	}
	//map->updateAvailableCores(-count);
	return valid;
}*/

bool Event::proposedMapping(Map* map) {
	double CCR = 0;
	for (auto task = tasks.begin(); task != tasks.end(); task++) {
		vector<int> c = task->getChildren();
		if (!c.empty()) {
			vector<double> withC = task->getWithNeibors();
			CCR = -withC[c[0]] / (*task).getExecutionVolume();
			break;
		}
	}

	
	if (CCR > 0.005) {
		int bubbleNum = 0;
		int bubbleNumLimit = map->getAvailableCores() - numTasks;
		int leastTime = -1;
		Vertex pin;
		vector<Vertex> notwork;
		Map mapMask = *map;
		for (int i = 0; i <= bubbleNumLimit; i++) {
			pin = book(mapMask,i, notwork);
			if (pin == Vertex(-1, -1, -1)) {
				notwork.push_back(pin);
				break;
			}
			if (cloestMapping_pin(pin, &mapMask) && thermalCheckMap(mapMask)) {
				int time = calculateRemainingTime(&mapMask);
				notwork.push_back(pin);
				//map->showMap();
				unhookFromMap(&mapMask);
				if (leastTime == -1) {
					leastTime = time;
					continue;
				}
				if (leastTime > time) {
					bubbleNum = i;
					leastTime = time;
				}
			}
			else {
				notwork.push_back(Vertex(-1, -1, -1));
				break;
			}
		}
		return cloestMapping_pin(notwork[bubbleNum],map,bubbleNum);
	}
	else {
		return farestMapping_pin(map);
	}

}

/*global*/
bool Event::farestMapping_pin(Map* map) {
	vector<Vertex> occupied;
	vector<vector<int>> distances;
	for (int k = 0; k < map->getLength(); k++) {
		for (int i = 0; i < map->getHeight(); i++) {
			for (int j = 0; j < map->getWidth(); j++) {
				vector<int> plate;
				distances.push_back(plate);
				Vertex temp(k, i, j);
				if (map->getSpecificCore(temp)->checkState()) {
					occupied.push_back(temp);
				}
			}
		}
	}

	for (vector<Vertex>::iterator iter = occupied.begin(); iter != occupied.end(); iter++) {
		for (int k = 0; k < map->getLength(); k++) {
			for (int i = 0; i < map->getHeight(); i++) {
				for (int j = 0; j < map->getWidth(); j++) {
					Vertex temp(k, i, j);
					if (!map->getSpecificCore(temp)->checkState()) {
						distances[map->toIndex(temp)].push_back((*iter).Manhattan(temp));
					}
					else {
						distances[map->toIndex(temp)].clear();
					}
				}
			}
		}
	}

	for (int count = 0; count < numTasks; count++) {
		auto maxLoca = max_element(distances.begin(), distances.end(), distanceComp);
		int location = std::distance(distances.begin(),maxLoca);
		Vertex selectedCore = map->toVertex(location);
		
		int coreCNT = 0;
		Map mapMask = *map;
		mapMask.turnOnCore(tasks[count], selectedCore);
		while (thermalCheckMap(mapMask)) {
			mapMask.turnOffCore(selectedCore);
			distances[location].clear();
			maxLoca = max_element(distances.begin(), distances.end(), distanceComp);
			location = std::distance(distances.begin(), maxLoca);
			selectedCore = map->toVertex(location);
			mapMask.turnOnCore(tasks[count], selectedCore);
			coreCNT++;
			//mapMask.showMap();
			if (coreCNT >= map->getAvailableCores()) {
				//mapMask.showMap();
				unhookFromMap(map);
				return false;
			}
		}
		map->turnOnCore(tasks[count], selectedCore);
		tasks.at(count).startRunning(selectedCore);

		occupied.push_back(selectedCore);
		for (int k = 0; k < map->getLength() && count < numTasks; k++) {
			for (int i = 0; i < map->getHeight() && count < numTasks; i++) {
				for (int j = 0; j < map->getWidth() && count < numTasks; j++) {
					Vertex temp(k, i, j);
					if (!map->getSpecificCore(temp)->checkState()) {
						distances[map->toIndex(temp)].push_back(selectedCore.Manhattan(temp));
					}
					else {
						distances[map->toIndex(temp)].clear();
					}
				}
			}
		}
	}
	return true;
}

bool Event::cloestMapping_pin(Vertex pin,Map * map,int bubbleNum)
{
	
	bool valid = true;
	Vertex center(pin.l, pin.h, pin.w);

	vector<int> distances;
	int max = map->getHeight()*map->getLength()*map->getWidth();
	for (int k = 0;  k < map->getLength(); k++) {
		for (int i = 0; i < map->getHeight(); i++) {
			for (int j = 0; j < map->getWidth(); j++) {
				Vertex temp(k, i, j);
				if (!map->getSpecificCore(temp)->checkState()) {
					distances.push_back(center.Manhattan(temp));
				}
				else {
					distances.push_back(max);
				}
			}
		}
	}

	int count = 0;
	Vertex temp = center;
	Map mapMask = *map;

	/*for (int i = 0; i <bubbleNum; i++) {
		auto task = &tasks[i];
		int index = std::distance(distances.begin(), min_element(distances.begin(), distances.end()));
		int l, h, w;
		l = index / (map->getHeight()*map->getWidth());
		h = (index - l*map->getHeight()*map->getWidth()) / map->getWidth();
		w = (index - l*map->getHeight()*map->getWidth()) % map->getWidth();

		distances[index] = max;
	}*/

	for (int i = 0; i < numTasks+bubbleNum; i++) {
		int index = std::distance(distances.begin(),min_element(distances.begin(), distances.end()));
		int l, h, w;
		l = index/(map->getHeight()*map->getWidth());
		h = (index - l*map->getHeight()*map->getWidth()) / map->getWidth();
		w = (index - l*map->getHeight()*map->getWidth()) % map->getWidth();
		if (i < bubbleNum) {
			distances[index] = max;
			continue;
		}
		auto task = &tasks[i - bubbleNum];
		temp = Vertex(l,h,w);
		mapMask.turnOnCore(*task, temp);
		while (thermalCheckMap(mapMask)) {
			mapMask.turnOffCore(temp);
			distances[index] = max;
			index = std::distance(distances.begin(), min_element(distances.begin(), distances.end()));
			l = index / (map->getHeight()*map->getWidth());
			h = (index - l*map->getHeight()*map->getWidth()) / map->getWidth();
			w = (index - l*map->getHeight()*map->getWidth()) % map->getWidth();
			temp = Vertex(l, h, w);
			mapMask.turnOnCore(*task, temp);
			count++;
			if (count > max) {
				unhookFromMap(map);
				return false;
			}
		}
		int x = map->toIndex(temp);
		map->turnOnCore(*task,temp);
		task->startRunning(temp);
		distances[x] = max;
	}

	return valid;
}

void Event::fillMapping(Map* map) {
	int count = 0;
	for (int k = 0; k < map->getLength() && count < numTasks; k++) {
		for (int i = 0; i < map->getHeight() && count < numTasks; i++) {
			for (int j = 0; j < map->getWidth() && count < numTasks; j++) {
				Vertex temp(k, i, j);
				if (!map->getSpecificCore(temp)->checkState()) {
					map->turnOnCore(tasks[count], temp);
					(tasks[count]).startRunning(temp);
				}
			}
		}
	}
	return;
}
bool Event::randomMapping(Map* map) {
	bool valid = true;
	for (auto task = tasks.begin(); task != tasks.end(); task++) {
		int count = 0;
		while (1) {
			count++;
			Vertex temp(rand() % map->getLength(), rand() % map->getHeight(), rand() % map->getWidth());
			if (!map->getSpecificCore(temp)->checkState() && (!thermalCheckCore(temp, *map))) {
				map->turnOnCore(*task, temp);
				(*task).startRunning(temp);
				break;
			}
			if (count > map->getHeight()*map->getWidth()*map->getLength()) {
				valid = false;
				break;
			}
		}
	}

	//map->updateAvailableCores(-numTasks);
	return valid;
}
